﻿using DataLayer;
using DataLayer.Model;
using FitbitAPI;
using FitbitAPI.Models;
using FitbitManager.WrapperLibrary;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FitbitManager.Subscripters
{
    class SubscripterManager
    {
        /// <summary>
        /// Manager the subscriptions of all the users
        /// </summary>
        public void SubscripterChecker()
        {
            RemoveFitbitAccounts();
            UpdateSubscriptions();
        }

        /// <summary>
        /// Force the subscription for all members
        /// </summary>
        public void SubscripterForced()
        {
            RemoveFitbitAccounts();
            AddAllUsersToSubscription();
        }

        private void AddAllUsersToSubscription()
        {
            UnitOfWork repository = UnitOfWork.CreateIntance();

            var accounts = repository.FitbitAccountRepository.GetAll();

            foreach (var account in accounts)
            {
                AddSubscription(account);
            }
            repository.Commit();
        }

        private void UpdateSubscriptions()
        {
            UnitOfWork repository = UnitOfWork.CreateIntance();

            var accounts = repository.FitbitAccountRepository.GetUnsubscribersAccounts();

            foreach (var account in accounts)
            {
                AddSubscription(account);// this save the user?
            }
            repository.Commit();
        }

        public void AddSubscription(FitbitAccount account)
        {
            FitbitAccount returnAccount = UpdateCredentialsTokens(account);

            WrapperFitbitClient client = WrapperFitbitClient.CreateFitbitClient(returnAccount.AccessToken, returnAccount.AccessSecret);

            bool susbcribed = false;

            try
            {
                susbcribed = client.ExistGameUpSubscription();
            }
            catch (FitbitException)
            {
                //User has revoked access. Update credentials
                returnAccount = UpdateCredentialsTokens(returnAccount, true);
                client = WrapperFitbitClient.CreateFitbitClient(returnAccount.AccessToken, returnAccount.AccessSecret);
            }

            if (!susbcribed)
            {
                var newOwnerID = client.AddSubscription(returnAccount.OwnerID);

                returnAccount.OwnerID = newOwnerID;
            }

            returnAccount.IsSubscribed = true;

            //Save?
        }

        private FitbitAccount UpdateCredentialsTokens(FitbitAccount account, bool force = false)
        {

            if (string.IsNullOrWhiteSpace(account.AccessSecret) || string.IsNullOrWhiteSpace(account.AccessToken) || string.IsNullOrWhiteSpace(account.OwnerID) || force)
            {
                string oauth_token = WrapperFitbitAuthenticator.GetAuthToken(); //TODO: Catch exception if error!
                string oauth_verifier = WrapperFitbitAuthenticator.GetAuthVerifier(account.UserName, account.Password, oauth_token);

                if (string.IsNullOrWhiteSpace(oauth_verifier))
                    throw new InvalidDataException("Invalid credentials.");

                AuthCredential newCredentials = WrapperFitbitAuthenticator.ProcessApprovedAuthCallback(oauth_token, oauth_verifier);

                account.OwnerID = newCredentials.UserId;
                account.AccessToken = newCredentials.AuthToken;
                account.AccessSecret = newCredentials.AuthTokenSecret;
            }

            return account;
        }

        private void RemoveFitbitAccounts()
        {
            UnitOfWork repository = UnitOfWork.CreateIntance();
            var FitbitAccounts = repository.FitbitAccountRepository.GetAccountShouldBeDelete();

            for (int i = FitbitAccounts.Count() - 1; i >= 0; i--)
            {
                RemoveSubscriptionAccount(FitbitAccounts.ElementAt(i));
                repository.FitbitAccountRepository.Delete(FitbitAccounts.ElementAt(i));
            }

            repository.Commit();
        }

        private void RemoveSubscriptionAccount(FitbitAccount fitbit)
        {
            WrapperFitbitClient client = WrapperFitbitClient.CreateFitbitClient(fitbit.AccessToken, fitbit.AccessSecret);

            try
            {
                client.RemoveSubscription(fitbit.OwnerID);
            }
            catch (FitbitException)
            {
                //User has revoked access. Don't care
                throw new Exception("Study this case!");
            }
        }

    }
}
